package com.tan.kotlintest.changeskin;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import com.tan.kotlintest.R;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;

public class SkinUtil implements LayoutInflater.Factory2 {

    private Context mContext;

    @SuppressLint("StaticFieldLeak")
    private static SkinUtil mSkinUtil;

    private SkinUtil() {
    }

    static SkinUtil getInstance() {
        if (mSkinUtil == null) {
            mSkinUtil = new SkinUtil();
        }
        return mSkinUtil;
    }

    private final Object[] mConstructorArgs = new Object[2];
    private static final HashMap<String, Constructor<? extends View>> sConstructorMap = new HashMap<>();
    private static final Class<?>[] mConstructorSignature = new Class[]{Context.class, AttributeSet.class};

    /**
     * 初始化
     */
    void init(Context context) {
        mContext = context;
        LayoutInflater.from(context).setFactory2(this);
    }

    /**
     * 收集Views
     */
    @Override
    public View onCreateView(View parent, String className, Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.support_change_skin);
        boolean isSupport = a.getBoolean(R.styleable.support_change_skin_support_skin, false);
        if (isSupport) {
            View view = createView(className, attrs);
            if (view != null) {
                for (int i = 0; i < attrs.getAttributeCount(); i++) {
                    String attrName = attrs.getAttributeName(i);
                    if (attrName.equals("background")) {//图片背景
                        String attribute = attrs.getAttributeValue(i);
                        Log.i("==--", "图片: " + attribute);
                        String[] content = attribute.split("@");
                        if (content.length > 1) {
                            String strId = content[1];
                            if (!TextUtils.isEmpty(strId) && TextUtils.isDigitsOnly(strId)) {
                                int resId = Integer.parseInt(strId);
                                if (resId > 0) {
                                    view.setBackground(getDrawable(resId));
                                }
                            }
                        }
                    } else if (attrName.equals("textColor")) {
                        String attribute = attrs.getAttributeValue(i);
                        Log.i("==--", "颜色: " + attribute);
                        String[] content = attribute.split("@");
                        if (content.length > 1) {
                            String strId = content[1];
                            if (!TextUtils.isEmpty(strId) && TextUtils.isDigitsOnly(strId)) {
                                int colorId = Integer.parseInt(strId);
                                if (colorId > 0) {
                                    ((TextView) view).setTextColor(getColor(colorId));
                                }
                            }
                        }
                    }
                }
            }
            return view;
        }
        a.recycle();
        return null;
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        return null;
    }

    /**
     * 创建View
     */
    private View createView(String name, AttributeSet attrs) {
        Constructor<? extends View> constructor = sConstructorMap.get(name);
        if (constructor != null && !verifyClassLoader(constructor)) {
            constructor = null;
            sConstructorMap.remove(name);
        }
        Class<? extends View> clazz;
        try {
            if (constructor == null) {
                // Class not found in the cache, see if it's real, and try to add it
                String className = "android.widget." + name;
                clazz = mContext.getClassLoader().loadClass(className).asSubclass(View.class);
                if (clazz != null) {
                    constructor = clazz.getConstructor(mConstructorSignature);
                    constructor.setAccessible(true);
                    sConstructorMap.put(className, constructor);
                }
            }  // If we have a filter, apply it to cached constructor
            Object lastContext = mConstructorArgs[0];
            if (mConstructorArgs[0] == null) {
                // Fill in the context if not already within inflation.
                mConstructorArgs[0] = mContext;
            }
            Object[] args = mConstructorArgs;
            args[1] = attrs;
            final View view;
            if (constructor != null) {
                view = constructor.newInstance(args);
                mConstructorArgs[0] = lastContext;
                return view;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static final ClassLoader BOOT_CLASS_LOADER = LayoutInflater.class.getClassLoader();

    private boolean verifyClassLoader(Constructor<? extends View> constructor) {
        final ClassLoader constructorLoader = constructor.getDeclaringClass().getClassLoader();
        if (constructorLoader == BOOT_CLASS_LOADER) {
            // fast path for boot class loader (most common case?) - always ok
            return true;
        }
        // in all normal cases (no dynamic code loading), we will exit the following loop on the
        // first iteration (i.e. when the declaring classloader is the contexts class loader).
        ClassLoader cl = mContext.getClassLoader();
        do {
            if (constructorLoader == cl) {
                return true;
            }
            cl = cl.getParent();
        } while (cl != null);
        return false;
    }

    /**
     * 获取drawable
     */
    private Drawable getDrawable(int resId) {
        Log.i("==--", "传入的图片ID: " + resId);
        //反射创建AssetManager 与 Resource
        AssetManager assetManager;
        try {
            String apkPath = Environment.getExternalStorageDirectory().getPath() + "/test.skin";
            File apkFile = new File(apkPath);
            if (!apkFile.exists()) {
                Log.i("==--", "未获取到文件");
                return null;
            }
            assetManager = AssetManager.class.newInstance();
            //资源路径设置 目录或压缩包
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, apkPath);
            //根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
            Resources resources = new Resources(assetManager, mContext.getResources().getDisplayMetrics(),
                    mContext.getResources().getConfiguration());
            //资源名
            String resourceEntryName = mContext.getResources().getResourceEntryName(resId);
            String resourceTypeName = mContext.getResources().getResourceTypeName(resId);
            Log.i("==--", "资源名: " + resourceEntryName + "   资源类型: " + resourceTypeName);
            //获取外部Apk(皮肤包) 包名
            PackageManager mPm = mContext.getPackageManager();
            PackageInfo info = mPm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
            String packageName = info.packageName;
            int identifier = resources.getIdentifier(resourceEntryName, resourceTypeName, packageName);
            return resources.getDrawable(identifier);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取color
     */
    private int getColor(int resId) {
        Log.i("==--", "传入的颜色ID: " + resId);
        //反射创建AssetManager 与 Resource
        AssetManager assetManager;
        try {
            String apkPath = Environment.getExternalStorageDirectory().getPath() + "/test.skin";
            File apkFile = new File(apkPath);
            if (!apkFile.exists()) {
                Log.i("==--", "未获取到文件");
                return 0;
            }
            assetManager = AssetManager.class.newInstance();
            //资源路径设置 目录或压缩包
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, apkPath);
            //根据当前的设备显示器信息 与 配置(横竖屏、语言等) 创建Resources
            Resources resources = new Resources(assetManager, mContext.getResources().getDisplayMetrics(),
                    mContext.getResources().getConfiguration());
            //资源名
            String resourceEntryName = mContext.getResources().getResourceEntryName(resId);
            String resourceTypeName = mContext.getResources().getResourceTypeName(resId);
            Log.i("==--", "资源名: " + resourceEntryName + "   资源类型: " + resourceTypeName);
            //获取外部Apk(皮肤包) 包名
            PackageManager mPm = mContext.getPackageManager();
            PackageInfo info = mPm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
            String packageName = info.packageName;
            int identifier = resources.getIdentifier(resourceEntryName, resourceTypeName, packageName);
            return resources.getColor(identifier);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

}
